package com.block.source.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.block.common.constant.RedisKeyConstant;
import com.block.common.enums.InfoTypeEnum;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.model.dto.SourceCountDTO;
import com.block.common.model.vo.ResultInfoVO;
import com.block.common.service.IApplicationInfoService;
import com.block.common.service.ISourceDataCountInfoService;
import com.block.common.service.LogFactory;
import com.block.common.service.impl.ChannelCommonServcie;
import com.block.datapush.special.service.ISpecialCostomInfoService;
import com.block.db.entity.*;
import com.block.source.enums.ReceiveTypeEnum;
import com.block.source.factory.SourceApiFactory;
import com.block.source.model.dto.SourceApiParam;
import com.block.source.model.dto.SourceApiResult;
import com.block.source.service.*;
import com.block.test.reqbean.source.CheckUserInfo;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class SourceHandleCheckUserServiceImpl implements ISourceHandleCheckUserService {

    private static Logger log = LogFactory.getSourceLog();
    private static Logger logTime = LogFactory.getTimeLog();

    @Autowired
    ISourceBaseInfoService sourceBaseInfoService;
    @Autowired
    IApplicationInfoService applicationInfoService;
    @Autowired
    ChannelCommonServcie channelCommonServcie;
    @Autowired
    ISpecialCostomInfoService specialCostomInfoService;
    @Autowired
    ISourceCheckUserService sourceCheckUserService;
    @Autowired
    NotifyExceptionService notifyExceptionService;
    @Autowired
    ISourcePushResultInfoService sourcePushResultInfoService;
    @Autowired
    ISourceRegisterUserService sourceRegisterUserService;
    @Autowired
    ISourceDataCountInfoService sourceDataCountInfoService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public JSONObject apiCheckUser(String channelCode, Map<String, String[]> parameterMap, String paramContent, String requestIp) {
        log.info("【线索api撞库】请求数据展示【channelCode】{}【parameterMap】{}【paramContent】{}", channelCode, JSON.toJSONString(parameterMap), paramContent);
        try {
            Long startTime = System.currentTimeMillis();
            // 查询基本信息
            SourceBaseInfo sourceBaseInfo = sourceBaseInfoService.getSourceInfo(channelCode);
            if (ObjectUtil.isEmpty(sourceBaseInfo)){
                JSONObject error = SourceApiFactory.getService(ReceiveTypeEnum.DEFAULT.getValue()).getError("渠道信息为空");
                return error;
            }

            Long time0 = System.currentTimeMillis();

            SourceCountDTO sourceCountDTO = new SourceCountDTO(sourceBaseInfo.getChannelCode(), sourceBaseInfo.getChannelName());
            sourceCountDTO.setCheckNumber(1);
            sourceDataCountInfoService.saveSourceCountInfo(sourceCountDTO);

            // 获取线索 对应的 处理类
            ISourceReceiveService sourceReceiveService = SourceApiFactory.getService(sourceBaseInfo.getFactoryType());
            if (!ObjectUtil.equals(sourceBaseInfo.getStatus(), Integer.valueOf(1))){
                JSONObject error = sourceReceiveService.getError("渠道信息不可用");
                return error;
            }
            //渠道类型为双授权，类型才是正确的
            if (!ObjectUtil.equals(sourceBaseInfo.getType(), InfoTypeEnum.APIS.getValue())){
                JSONObject error = sourceReceiveService.getError("渠道类型错误，非双授权");
                return error;
            }

            Long time1 = System.currentTimeMillis();

            // 根据请求信息，构造需要的参数信息
            SourceApiResult sourceApiResult = sourceReceiveService.handleCheckUserData(sourceBaseInfo, parameterMap, paramContent);
            log.info("【线索api撞库】撞库数据转换完毕【channelCode】{}【sourceApiResult】{}", channelCode, JSON.toJSONString(sourceApiResult));
            if (!sourceApiResult.isSuccess()){
                return sourceApiResult.getReturnObject();
            }

            Long time2 = System.currentTimeMillis();

            // 执行撞库操作
            CheckUserInfo checkUserInfo = sourceApiResult.getCheckUserInfo();
            checkUserInfo.setUserIp(requestIp);

            // 撞库参数校验
            String respMsg = ISourceReceiveService.verifyCheckUserParam(checkUserInfo);
            // 返回信息不为空，则有异常，直接返回
            if (StrUtil.isNotEmpty(respMsg)) {
                log.info("【线索api撞库】撞库数据检验【channelCode】{}【verifyRes】{}", channelCode, respMsg);
                return sourceReceiveService.getError(respMsg);
            }

            Long time3 = System.currentTimeMillis();
            //
            ChannelInfo channelBaseInfo = channelCommonServcie.getChannelInfoCache(channelCode);
            ApplicationInfo applicationInfo = applicationInfoService.getAppInfoByType(channelBaseInfo.getAppType());

            Long time4 = System.currentTimeMillis();

            ResultInfoVO resultInfoVO = sourceCheckUserService.sourceCheckUser1(sourceBaseInfo, checkUserInfo, channelBaseInfo, applicationInfo);
            log.info("【线索api撞库】数据撞库完成【channelCode】{}【resultInfoVO】{}", channelCode, JSON.toJSONString(resultInfoVO));
            if (!resultInfoVO.isSuccess()){
                return sourceReceiveService.getError(resultInfoVO.getRespMsg());
            }

            Long time5 = System.currentTimeMillis();

            // 根据返回结果，构造渠道方需要的数据
            JSONObject data = resultInfoVO.getData();
            String status = data.getString("status");
            if (!StrUtil.equals(status, "000")){
                return sourceReceiveService.getError("撞库失败");
            }

            Long time6 = System.currentTimeMillis();

            String orderNo = data.getString("orderNo");

            SourcePushResultInfo sourcePushResultInfo = sourcePushResultInfoService.getById(orderNo);
            SpecialCostomInfo specialCostomInfo = specialCostomInfoService.getById(sourcePushResultInfo.getInfoId());

            MerchantThirdBaseInfo thirdBaseInfo = data.getObject("thirdBaseInfo", MerchantThirdBaseInfo.class);
            List<MerchantThirdProtocolInfo> thirdProtocolInfoList = data.getObject("thirdProtocolInfoList", List.class);

            SourceApiParam sourceApiParam = new SourceApiParam();
            sourceApiParam.setSourcePushResultInfo(sourcePushResultInfo);
            sourceApiParam.setSpecialCostomInfo(specialCostomInfo);
            sourceApiParam.setThirdBaseInfo(thirdBaseInfo);
            sourceApiParam.setThirdProtocolInfoList(thirdProtocolInfoList);
            sourceApiParam.setExtObject(sourceApiResult.getExtObject());

            Long time7 = System.currentTimeMillis();

            // 根据请求信息，构造需要的参数信息
            SourceApiResult checkUserResult = sourceReceiveService.getCheckUserReturnData(sourceBaseInfo, resultInfoVO, sourceApiParam);
            Long entTime = System.currentTimeMillis();
            Long execTime = entTime - startTime;

            logTime.info("【exexTime】{}【entTime - time7】{}【time7 - time6】{}【time6 - time5】{}【time5 - time4】{}【time4 - time3】{}【ime3 - time2】{}【time2 - time1】{}【time1 - startTime】{}",
                    execTime, entTime - time7, time7 - time6, time6 - time5, time5 - time4, time4 - time3, time3 - time2, time2 - time1, time1 - startTime );
            // 返回数据
            log.info("【线索api撞库】请求完成，返回撞库数据【channelCode】{}【execTime】{}【checkUserResult】{}", channelCode, execTime, JSON.toJSONString(checkUserResult));

            if (!checkUserResult.isSuccess()){
                // 删除撞库锁
                // 分润渠道，可能因为价格太低，返回撞库失败
                String mobileLockKey = StrUtil.format(RedisKeyConstant.SOURCE_CHECK_MOBILEMD5_LOCK_KEY, checkUserInfo.getMobileMd5());
                stringRedisTemplate.delete(mobileLockKey);
            }
            return checkUserResult.getReturnObject();
        }catch (Exception exception){
            log.error("线索api撞库异常", exception);
        }
        return SourceApiFactory.getService(ReceiveTypeEnum.DEFAULT.getValue()).getError("撞库异常");
    }


    @Override
    public JSONObject apiRegisterUser(String channelCode, Map<String, String[]> parameterMap, String paramContent, String requestIp){
        log.info("【线索api进件】请求数据展示【channelCode】{}【parameterMap】{}【paramContent】{}", channelCode, JSON.toJSONString(parameterMap), paramContent);
        try {

            // 查询基本信息
            SourceBaseInfo sourceBaseInfo = sourceBaseInfoService.getSourceInfo(channelCode);
            if (ObjectUtil.isEmpty(sourceBaseInfo)){
                JSONObject error = SourceApiFactory.getService(ReceiveTypeEnum.DEFAULT.getValue()).getError("渠道信息为空");
                return error;
            }

            SourceCountDTO sourceCountDTO = new SourceCountDTO(sourceBaseInfo.getChannelCode(), sourceBaseInfo.getChannelName());
            sourceCountDTO.setRegisterNumber(1);
            sourceDataCountInfoService.saveSourceCountInfo(sourceCountDTO);

            ISourceReceiveService sourceReceiveService = SourceApiFactory.getService(sourceBaseInfo.getFactoryType());
            if (!ObjectUtil.equals(sourceBaseInfo.getStatus(), Integer.valueOf(1))){
                JSONObject error = sourceReceiveService.getError("渠道信息不可用");
                return error;
            }
            if (!ObjectUtil.equals(sourceBaseInfo.getType(), InfoTypeEnum.APIS.getValue())){
                JSONObject error = sourceReceiveService.getError("渠道类型错误，非双授权");
                return error;
            }

            // 根据请求信息，构造需要的参数信息
            SourceApiResult sourceApiResult = sourceReceiveService.handleRegisterUserData(sourceBaseInfo, parameterMap, paramContent);
            log.info("【线索api进件】进件数据转换完毕【channelCode】{}【sourceApiResult】{}", sourceBaseInfo.getChannelCode(), JSON.toJSONString(sourceApiResult));
            if (!sourceApiResult.isSuccess()){
                return sourceApiResult.getReturnObject();
            }
            if (StrUtil.isBlank(sourceApiResult.getCheckUserInfo().getRealName())) {
                JSONObject error = sourceReceiveService.getError("姓名不能为空");
                return error;
            }
            CheckUserInfo userDataParam = sourceApiResult.getCheckUserInfo();
            userDataParam.setUserIp(requestIp);

            // 进行数据进件
            ResultInfoVO resultInfoVO = sourceRegisterUserService.sourceRegisterUser1(userDataParam.getOrderNo(), sourceBaseInfo, userDataParam);

            log.info("【线索api进件】数据进件完成【channelCode】{}【resultInfoVO】{}", channelCode, JSON.toJSONString(resultInfoVO));
            if (!resultInfoVO.isSuccess()){
                return sourceReceiveService.getError(resultInfoVO.getRespMsg());
            }

            // 根据返回结果，构造渠道方需要的数据
            JSONObject data = resultInfoVO.getData();

            MerchantThirdBaseInfo thirdBaseInfo = data.getObject("thirdBaseInfo", MerchantThirdBaseInfo.class);
            List<MerchantThirdProtocolInfo> thirdProtocolInfoList = data.getObject("thirdProtocolInfoList", List.class);

            // 根据请求信息，构造需要的参数信息
            SourceApiParam sourceApiParam = new SourceApiParam();
            sourceApiParam.setExtObject(sourceApiResult.getExtObject());

            SourcePushResultInfo sourcePushResultInfo = sourcePushResultInfoService.getById(userDataParam.getOrderNo());

            SpecialCostomInfo specialCostomInfo = specialCostomInfoService.getById(sourcePushResultInfo.getInfoId());
            sourceApiParam.setSpecialCostomInfo(specialCostomInfo);
            sourceApiParam.setSourcePushResultInfo(sourcePushResultInfo);

            sourceApiParam.setThirdBaseInfo(thirdBaseInfo);
            sourceApiParam.setThirdProtocolInfoList(thirdProtocolInfoList);

            SourceApiResult checkUserResult = sourceReceiveService.getRegisterUserReturnData(sourceBaseInfo, resultInfoVO,sourceApiParam);

            if (resultInfoVO.isSuccess()){

                sourceCountDTO.setRegisterPassNumber(1);
                sourceCountDTO.setRegisterNumber(null);
                sourceDataCountInfoService.saveSourceCountInfo(sourceCountDTO);
            }

            // 返回数据
            log.info("【线索api进件】请求完成，返回进件数据【channelCode】{}【checkUserResult】{}", channelCode, JSON.toJSONString(checkUserResult));
            return checkUserResult.getReturnObject();
        }catch (Exception exception){
            log.error("线索api进件异常", exception);
        }
        return SourceApiFactory.getService(ReceiveTypeEnum.DEFAULT.getValue()).getError("进件异常");
    }

}
